#include "msghandler.h"
#include <QDebug>
#include "protocol.h"
#include "operatedb.h"
#include "msghandler.h"
#include "mytcpserver.h"
#include "server.h"
#include <QDir>

MsgHandler::MsgHandler()
{
    m_bUpload = false;
    m_bDownload = false;
}

PDU *MsgHandler::handleRegist(PDU *pdu)
{
    char caName[32] = {'\0'};
    char caPwd[32] = {'\0'};
    memcpy(caName, pdu->caData,32);
    memcpy(caPwd, pdu->caData + 32, 32);
    qDebug() << "recvMsg regist caName:" << caName
             << "caPwd:" << caPwd;
    bool ret = OperateDb::getInstance().handleRegist(caName, caPwd);//单例模式
    if(ret){
        QDir dir;//注册时服务器新建一个用户文件夹
        dir.mkdir(QString("%1/%2").arg(Server::getInstance().m_rootDir).arg(caName));
    }
    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_REGIST_RESPOND;
    memcpy(respdu->caData, &ret, sizeof(bool));
    return respdu;
}

PDU *MsgHandler::handleLogin(PDU *pdu,QString& LoginName)
{
    char caName[32] = {'\0'};
    char caPwd[32] = {'\0'};
    memcpy(caName, pdu->caData,32);
    memcpy(caPwd, pdu->caData + 32, 32);
    qDebug() << "recvMsg login caName:" << caName
             << "caPwd:" << caPwd;
    bool ret = OperateDb::getInstance().handleLogin(caName, caPwd);//单例模式
    if(ret)
    {
        LoginName = caName;
    }
    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_LOGIN_RESPOND;
    memcpy(respdu->caData, &ret, sizeof(bool));
    return respdu;
}

PDU *MsgHandler::handleFindUser(PDU *pdu)
{
    char caName[32] = {'\0'};
    memcpy(caName, pdu->caData,32);
    qDebug() << "recvMsg find user caName:" << caName;
    int ret = OperateDb::getInstance().handleFindUser(caName);//单例模式
    PDU* respdu = mkPDU(0);//构建PDU
    respdu->uiMsgType = ENUM_MSG_TYPE_FIND_USER_RESPOND;//类型
    memcpy(respdu->caData, caName, 32);//存caData，发送给客户端
    memcpy(respdu->caData + 32, &ret, sizeof(int));//存caData偏移量+32，发送给客户端
    return respdu;
}

PDU *MsgHandler::handleOnlineUser()
{
    qDebug() << "recvMsg online user start";
    QStringList result = OperateDb::getInstance().handleOnlineUser();//单例模式
    qDebug() << result;
    uint uiMsgLen = result.size()*32;//存一下
    PDU* respdu = mkPDU(uiMsgLen);//构建PDU
    respdu->uiMsgType = ENUM_MSG_TYPE_ONLINE_USER_RESPOND;//类型
    for(int i = 0; i < result.size(); i++)
    {
        qDebug() << "result.at(i)" <<result.at(i);
        memcpy(respdu->caMsg+i*32,result.at(i).toStdString().c_str(),result.at(i).size());//发送
    }
    return respdu;
}

PDU *MsgHandler::handleAddFriend(PDU *pdu)
{
    //当前用户和目标用户的名字取出来
    char curName[32] = {'\0'};
    char tarName[32] = {'\0'};
    memcpy(curName, pdu->caData,32);
    memcpy(tarName, pdu->caData + 32, 32);
    qDebug() << "recvMsg handleAddFriend curName:" << curName
             << "tarName:" << tarName;
    int ret = OperateDb::getInstance().handleAddFriend(curName, tarName);//单例模式
    if(ret == 1)//判断
    {
        MyTcpServer::getInstance().resend(tarName,pdu);//需要pdu的信息
    }
    PDU* respdu = mkPDU(0);//构建pdu
    respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_RESPOND;//pdu类型
    memcpy(respdu->caData, &ret, sizeof(int));//目标用户名放入caData里
    return respdu;
}

PDU *MsgHandler::handleAddFriendAgree(PDU *pdu)
{
    char caCurName[32] = {'\0'};
    char caTarName[32] = {'\0'};
    memcpy(caCurName, pdu->caData,32);
    memcpy(caTarName, pdu->caData + 32, 32);
    qDebug() << "recvMsg handleAddFriendAgree caCurName:" << caCurName
             << "caTarName:" << caTarName;
    OperateDb::getInstance().handleAddFriendAgree(caCurName, caTarName);
    //发给tar
    PDU* respdu = mkPDU(0);//构建pdu
    respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_AGREE_RESPOND;//pdu类型
    MyTcpServer::getInstance().resend(caCurName, respdu);//转发给cur
    return respdu;
}

PDU *MsgHandler::handleOnlineFriend(PDU *pdu)
{
    qDebug() << "handleOnlineFriend online friend start";
    QStringList result = OperateDb::getInstance().handleOnlineFriend(pdu->caData);//单例模式
    uint uiMsgLen = result.size()*32;//存一下
    PDU* respdu = mkPDU(uiMsgLen);//构建PDU
    respdu->uiMsgType = ENUM_MSG_TYPE_ONLINE_FRIEND_RESPOND;//类型
    qDebug() <<"PDU *MsgHandler::handleOnlineFriend result.size()" << result.size();
    for(int i = 0; i < result.size(); i++)
    {
        qDebug() << "handleOnlineFriend result.at(i)" <<result.at(i);
        memcpy((char*)(respdu->caMsg)+i*32,result.at(i).toStdString().c_str(),result.at(i).size());//发送
    }
    return respdu;
}

PDU *MsgHandler::handleDelFriend(PDU *pdu)//调用删除好友函数
{
    char curName[32] = {'\0'};
    char tarName[32] = {'\0'};
    memcpy(curName, pdu->caData,32);
    memcpy(tarName, pdu->caData + 32, 32);
    qDebug() << "recvMsg handleDelFriend curName:" << curName
             << "tarName:" << tarName;
    bool ret = OperateDb::getInstance().handleDelFriend(curName, tarName);
    PDU* respdu = mkPDU(0);//构建pdu
    respdu->uiMsgType = ENUM_MSG_TYPE_DEL_FRIEND_RESPOND;
    memcpy(respdu->caData, &ret, sizeof(bool));//目标用户名放入caData里
    return respdu;
}

void MsgHandler::handleChat(PDU *pdu)//服务器转发消息
{
    char caTarName[32] = {'\0'};
    memcpy(caTarName, pdu->caData + 32, 32);
    qDebug() << "handleChat tarName: " << caTarName;
    MyTcpServer::getInstance().resend(caTarName, pdu);
}

PDU *MsgHandler::handleMKDIR(PDU *pdu)
{
    PDU* respdu = mkPDU(0);// 构建响应PDU
    respdu->uiMsgType = ENUM_MSG_TYPE_MKDIR_REQUEST;// 设置响应PDU类型为创建文件夹请求
    bool res = false;// 创建结果，默认为false
    QString strCurPath = pdu->caMsg;// 获取当前路径
    QDir dir;// 创建目录对象
    //如果创建文件夹的所在路径不存在，返回false
    if(!dir.exists(strCurPath)){
        qDebug()<<"handleMKDIR"<<!dir.exists(strCurPath);
        memcpy(respdu->caData,&res,sizeof(bool));
        return respdu;
    }
    char caNewDir[32] = {'\0'};// 获取新建文件夹的名称
    memcpy(caNewDir,pdu->caData,32);
    QString strNewPath = QString("%1/%2").arg(strCurPath).arg(caNewDir);// 构建新的完整路径
    //如果创建文件夹的完整路径已经存在或者创建失败，返回false
    if(dir.exists(strNewPath) || !dir.mkdir(strNewPath)){
        memcpy(respdu->caData,&res,sizeof(bool));
        return respdu;
    }
    res = true;// 创建成功，将结果设置为true
    memcpy(respdu->caData,&res,sizeof(bool));
    return respdu;// 返回响应PDU
}

PDU *MsgHandler::handleFlushFile(PDU *pdu)
{
    QString strCurPath = pdu->caMsg;// 获取当前路径
    QDir dir(strCurPath);// 创建目录对象
    QFileInfoList fileInfoList = dir.entryInfoList();// 获取目录下的文件信息列表

    PDU* respdu = mkPDU((fileInfoList.size()-2) * sizeof(FileInfo));//构建响应PDU
    respdu->uiMsgType = ENUM_MSG_TYPE_FLUSH_FILE_RESPOND;//设置响应PDU类型

    FileInfo* pFileInfo = NULL;// 文件信息指针赋值为空
    QString strFileName;// 定义文件名
    for(int i = 0, j = 0; i < fileInfoList.size(); i++){// 遍历文件信息列表
        strFileName = fileInfoList[i].fileName();//获取文件名
        if(strFileName == QString(".") || strFileName == QString("..")){//.和..过滤掉
            continue;
        }
        pFileInfo = (FileInfo*)respdu->caMsg+j++;// 获取文件信息指针
        memcpy(pFileInfo->caName,strFileName.toStdString().c_str(),strFileName.size());// 将文件名拷贝到文件信息中
        // 判断文件类型
        if(fileInfoList[i].isDir()){
            pFileInfo->FileType = 0;// 目录
        }
        else if(fileInfoList[i].isFile()){
            pFileInfo->FileType = 1;// 文件
        }
        qDebug()<<"handleFlushFile strFileName" <<strFileName;
    }
    return respdu;
}

PDU *MsgHandler::handleDelDir(PDU *pdu)
{
    char* pPath = pdu->caMsg;
    QFileInfo fileInfo(pPath);
    bool ret = false;
    if(fileInfo.isDir()){
        QDir dir;
        dir.setPath(pPath);
        ret = dir.removeRecursively();//递归删除
    }
    PDU* respdu = mkPDU(0);
    memcpy(respdu->caData,&ret,sizeof(bool));
    respdu->uiMsgType = ENUM_MSG_TYPE_DEL_DIR_RESPOND;
    return respdu;
}

PDU *MsgHandler::handleRenameFile(PDU *pdu)
{
    char caOldFileName[32] = {'\0'};
    char caNewFileName[32] = {'\0'};
    memcpy(caOldFileName,pdu->caData,32);
    memcpy(caNewFileName,pdu->caData+32,32);
    char* pPath = pdu->caMsg;
    QString strOldPath = QString("%1/%2").arg(pPath).arg(caOldFileName);
    QString strNewPath = QString("%1/%2").arg(pPath).arg(caNewFileName);

    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_RENAME_FILE_RESPOND;
    QDir dir;
    bool ret = dir.rename(strOldPath,strNewPath);
    memcpy(respdu->caData,&ret,sizeof(bool));
    return respdu;
}

PDU *MsgHandler::handleDelFile(PDU *pdu)
{
    char* pPath = pdu->caMsg;
    QFileInfo fileInfo(pPath);
    bool ret = false;
    if(fileInfo.isDir()){
        QDir dir;
        dir.setPath(pPath);
        ret = dir.remove(0);
    }
    PDU* respdu = mkPDU(0);
    memcpy(respdu->caData,&ret,sizeof(bool));
    respdu->uiMsgType = ENUM_MSG_TYPE_DEL_DIR_RESPOND;
    return respdu;
}

PDU *MsgHandler::handleMoveFile(PDU *pdu)
{
    //取出路径
    int srcLen = 0;
    int tarLen = 0;
    memcpy(&srcLen,pdu->caData,sizeof(int));
    memcpy(&tarLen,pdu->caData+32,sizeof(int));

    char* pSrcPath = new char[srcLen+1];
    char* pTarPath = new char[tarLen+1];

    //清空
    memset(pSrcPath,'\0',srcLen+1);
    memset(pTarPath,'\0',tarLen+1);

    memcpy(pSrcPath,pdu->caMsg,srcLen+1);
    memcpy(pTarPath,pdu->caMsg+srcLen+1,tarLen+1);
    qDebug()<<"pSrcPath:"<<pSrcPath
            <<"tarLen:"<<pTarPath;

    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_MOVE_FILE_RESPOND;
    bool ret = QFile::rename(pSrcPath,pTarPath);
    memcpy(respdu->caData,&ret,sizeof (bool));

    delete [] pSrcPath;
    delete [] pTarPath;
    pSrcPath = NULL;
    pTarPath = NULL;
    return respdu;
}

PDU *MsgHandler::handleUploadFile(PDU *pdu)
{
    //构建PDU
    PDU* respdu = mkPDU(0);
    int ret = 0;
    respdu->uiMsgType = ENUM_MSG_TYPE_UPLOAD_FILE_RESPOND;
    //判断是否已有文件在上传，已有响应1
    if(m_bUpload){
        ret = 1;
        memcpy(respdu->caData,&ret,sizeof(int));
        return respdu;
    }
    //取出文件名、文件大小、拼接完整目标路径
    char caFileName[32] = {'\0'};
    qint64 iFileSize = 0;
    memcpy(caFileName,pdu->caData,32);
    memcpy(&iFileSize,pdu->caData+32,sizeof(qint64));
    qDebug()<<"caFileName" <<caFileName
           <<"iFileSize" <<iFileSize;
    QString strPath = QString("%1/%2").arg(pdu->caMsg).arg(caFileName);
    //打开文件，如果成功更新文件属性，失败响应-1
    m_fUploadFile.setFileName(strPath);
    if(m_fUploadFile.open(QIODevice::WriteOnly)){
        m_bUpload = true;//是否上传文件成功
        m_iUploadTotal = iFileSize;//文件总的大小
        m_iUploadReceived = 0;//已经上传的文件大小
    }else{
        ret = -1;
    }
    memcpy(respdu->caData, &ret, sizeof(int));
    return respdu;
}

PDU *MsgHandler::handleUploadFileData(PDU *pdu)//上传文件数据
{
    //caMsg中的文件内容写入上传文件对象
    m_fUploadFile.write(pdu->caMsg, pdu->uiMsgLen);
    //更新已接收文件大小
    m_iUploadReceived += pdu->uiMsgLen;
    //没有全部接收完，不响应继续接收
    if(m_iUploadReceived < m_iUploadTotal){
        return  NULL;
    }
    //关闭文件，更新上传文件状态
    m_fUploadFile.close();
    m_bUpload = false;
    //响应结果
    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_UPLOAD_FILE_DATA_RESPOND;
    bool ret = m_iUploadReceived == m_iUploadTotal;
    memcpy(respdu->caData, &ret, sizeof(bool));
    return respdu;
}

PDU *MsgHandler::handleDownloadFile(PDU *pdu)
{
    qDebug() << "handleDownloadFile start";
    //构建PDU
    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_DOWNLOAD_FILE_RESPOND;
    int ret = 0;
    //判断是否已有文件在下载，已有响应1
    if(m_bDownload){
        ret = 1;
        memcpy(respdu->caData,&ret,sizeof(int));
        return respdu;
    }
    QFileInfo fileInfo(pdu->caMsg);
    qint64 iFileSize = fileInfo.size();
    //打开文件，如果成功更新文件属性，失败响应-1
    m_fDownloadFile.setFileName(pdu->caMsg);
    if(m_fDownloadFile.open(QIODevice::ReadOnly)){
        m_bDownload = true;
    }else{
        ret = -1;
    }
    qDebug() << "handleDownloadFile ret "<< ret;
    memcpy(respdu->caData, &ret, sizeof(int));
    memcpy(respdu->caData+32, &iFileSize, sizeof(qint64));
    qDebug() << "handleDownloadFile end ";
    return respdu;
}

PDU *MsgHandler::handleDownloadFileData(MyTcpSocket *socket)
{
    qDebug() << "handleDownloadFileData start ";
    //循环读取并发送文件内容给客户端
    PDU* respdu = mkPDU(4096);
    respdu->uiMsgType = ENUM_MSG_TYPE_DOWNLOAD_FILE_DATA_RESPOND;
    qint64 ret = 0;
    while(true){
        ret = m_fDownloadFile.read(respdu->caMsg, 4096);
        if(ret <= 0){
            break;
        }
        respdu->uiMsgLen = ret;
        respdu->uiPDULen = ret + sizeof(PDU);
        socket->write((char*)respdu, respdu->uiPDULen);
    }

    //发送完数据更新下载文件的属性，关闭文件
    m_bDownload = false;
    m_fDownloadFile.close();
    free (respdu);
    respdu = NULL;
    qDebug() << "handleDownloadFileData end ";
    return NULL;
}

PDU *MsgHandler::handleShareFile(PDU *pdu)
{
    qDebug() << "handleShareFile start";
    //取出当前用户名和好友数量
    char strCurName[32] = {'\0'};
    int friendNum = 0;
    memcpy(strCurName, pdu->caData, 32);
    memcpy(&friendNum, pdu->caData+32, sizeof(int));

    //构建转发pdu，文件路径放入caMsg，当前用户名放入caData
    int size = friendNum*32;
    PDU* resendpdu = mkPDU(pdu->uiMsgLen - size);
    resendpdu->uiMsgType = pdu->uiMsgType;
    memcpy(resendpdu->caMsg, pdu->caMsg + size, pdu->uiMsgLen - size);
    memcpy(resendpdu->caData, strCurName, 32);

    //遍历好友转发
    char caRecvName[32] = {'\0'};
    for(int i = 0; i < friendNum; i++){
        memcpy(caRecvName, pdu->caMsg + i * 32, 32);
        MyTcpServer::getInstance().resend(caRecvName, resendpdu);
    }
    //释放
    free(resendpdu);
    resendpdu = NULL;

    //服务器响应给当前用户
    PDU* respdu = mkPDU(0);
    respdu->uiMsgType = ENUM_MSG_TYPE_SHARE_FILE_RESPOND;
    qDebug() << "handleShareFile end";
    return respdu;
}

PDU *MsgHandler::handleShareFileAgree(PDU *pdu)
{
    //拼接接收路径:用户根目录
    //接收文件路径
    QString strRecvPath = QString("%1/%2").arg(Server::getInstance().m_rootDir).arg(pdu->caData);
    //分享文件路径
    QString strSharePath = pdu->caMsg;

    //获取文件名，拼接接收的完整路径
    //分享文件名
    QString strShareFileName = strSharePath.right(strSharePath.size() - strSharePath.lastIndexOf('/') - 1);
    //拼接完整路径名
    QString strPath = strRecvPath + "/" + strShareFileName;

    //通过QFileInfo对象进行复制
    QFileInfo fileInfo(strSharePath);
    bool ret = true;
    if (fileInfo.isFile()) {
        ret = QFile::copy(strSharePath, strPath);
        qDebug() << "handleShareFileAgree is file ret: " << ret;
    }
    else if(fileInfo.isDir()) {
        //复制目录
        ret = copyDir(strSharePath, strPath);
    }
    //发送pdu
    PDU* respdu = mkPDU(0);
    memcpy(respdu->caData, &ret, sizeof(bool));
    respdu->uiMsgType = ENUM_MSG_TYPE_SHARE_FILE_AGREE_RESPOND;
    return respdu;
}

bool MsgHandler::copyDir(QString strSrcDir, QString strDestDir)
{
    //创建目标目录
    QDir dir;
    dir.mkdir(strDestDir);
    //获取原目录下的文件信息列表
    dir.setPath(strSrcDir);
    QFileInfoList fileInfoList = dir.entryInfoList();
    bool ret = true;
    QString srcTmp;
    QString destTmp;
    //遍历目录下的文件
    for (int i = 0; i < fileInfoList.size(); i++) {
        //复制文件
        if (fileInfoList[i].isFile()) {
            srcTmp = strSrcDir + '/' + fileInfoList[i].fileName();
            destTmp = strSrcDir + '/' + fileInfoList[i].fileName();
            if (!QFile::copy(srcTmp, destTmp)) {
                ret = false;
            }
        }
        else if (fileInfoList[i].isDir()) {
            //过滤.和..
            if (fileInfoList[i].fileName() == QString(".") || fileInfoList[i].fileName() == QString("..")) {
                continue;
            }
            //拼接目录的完整路径，递归调用
            srcTmp = strSrcDir + '/' + fileInfoList[i].fileName();
            destTmp = strDestDir + '/' + fileInfoList[i].fileName();
            if (!copyDir(srcTmp, destTmp)) {
                ret = false;
            }
        }
    }
    return ret;
}
